package com.cccyy.lottery;


import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

public class LotteryWithAwardItem {

    public static void main(String[] args) {
        LotteryWithAwardItem m = new LotteryWithAwardItem();
        //mode 1单次抽 2连连抽
        int mode = 10;
        m.draw(mode);
    }

    /**
     * 初始化奖池
     *
     * @return 奖池
     */
    public List<AwardItem> initAwardItem() {
        List<AwardItem> list = new ArrayList<>(); //此处查数据库 获取 库存>0 且 概率>0 的奖项
        list.add(new AwardItem(1, 1, 10000, "iphone"));
        list.add(new AwardItem(2, 3, 10000, "耳机"));
        list.add(new AwardItem(3, 5, 10000, "周卡"));
        list.add(new AwardItem(4, 10, 10000, "U盘"));
        list.add(new AwardItem(5, 20, 10000, "100元券"));
        list.add(new AwardItem(6, 30, 10000, "300元券"));
        list.add(new AwardItem(7, 50, 10000, "500元券"));

        // 若无结果，则提示活动结束
        if (list.size() == 0) {
            throw new RuntimeException("正在努力补货中......");
        }

        // 业务处理，过滤掉本次不能抽中的奖项（自行处理）

        return list;
    }

    /**
     * 抽奖
     *
     * @param mode 1单次抽 2连连抽
     */
    void draw(int mode) {
        String uid = "12345678"; // 当前登录用户
        // 1 检查 是否当前用户还有抽奖次数
        int drawCount = 10; // 此处查询数据库当前用户本次活动还剩余的抽奖次数
        if (drawCount < 1) {
            throw new RuntimeException("您的抽奖次数已经用完");
        }

        // 计算本次循环抽多少次
        // 1、如果是单次抽 循环1次
        int count = 1;
        // 2、如果是连连抽
        if (mode == 2) {
            count = 10; // 查询连连抽的次数
        }

        int usedCount = 0; //本轮抽奖所使用的次数
        while (usedCount < count) {
            usedCount++;
            List<AwardItem> list = initAwardItem();
            int awardItemId = doDraw(list);
            for (AwardItem awardItem : list) {
                if (awardItemId == awardItem.getId()) {
                    System.out.println("抽奖抽到的奖品: " + awardItem.getName());
                }
            }
            if (awardItemId == -1) {
                throw new RuntimeException("未中奖");
            }
            // 用当前奖品ID加redis锁（key='DRAW_ITEM_'+awardItemId），扣库存，剪掉用户本次抽奖次数
            try {
                // 处理中奖的数据
                processingTheWinningData(awardItemId, uid);
            } finally {
                // 此处解锁redis锁(key='DRAW_ITEM_'+awardItemId)
            }
        }
    }

    /**
     * 处理中奖数据
     *
     * @param awardItemID 奖项id
     * @param uid         用户id
     */
    void processingTheWinningData(int awardItemID, String uid) {
        // 插入中奖记录 扣减中奖奖品的库存 和 用户抽奖次数
        // 此处加事务
        System.out.println("插入中奖记录 扣减中奖奖品的库存 和 用户抽奖次数");
    }

    /**
     * 执行抽奖
     *
     * @param list 奖池
     * @return 中奖的奖项ID
     */
    int doDraw(List<AwardItem> list) {
        // 计算所有奖项权重总和
        int sumWeight = list.stream().mapToInt(AwardItem::getProbability).sum();

        // 此次中奖的随机数
        SecureRandom secureRandom = new SecureRandom();
        double v = secureRandom.nextDouble();
        int randomNum = (int) (v * sumWeight);
        int min = 0;
        int max = 0;
        int selected = -1;

        // 遍历奖池，找出中奖的奖项
        for (int i = 0; i < list.size(); i++) {
            if (i > 0) {
                min = max;
            }
            max += list.get(i).getProbability();
            if (randomNum >= min && randomNum < max) {
                selected = i;
                break;
            }
        }

        return selected == -1 ? selected : list.get(selected).getId();
    }

    /**
     * 奖项
     */
    class AwardItem {
        int id;
        int probability; // 概率
        int stock; // 库存
        String name;

        public AwardItem(int id, int probability, int stock, String name) {
            this.id = id;
            this.probability = probability;
            this.stock = stock;
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public int getProbability() {
            return probability;
        }

        public void setProbability(int probability) {
            this.probability = probability;
        }

        public int getStock() {
            return stock;
        }

        public void setStock(int stock) {
            this.stock = stock;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

}
